<template>
  <div class="map" :id="mapId" ref="mapRef"></div>
</template>

<script setup>
import { onMounted, reactive, ref, useTemplateRef, nextTick, onUnmounted } from 'vue';
import { loadMapSource, loadMapEditSource, getMapInstance } from '@/utils/map'
import { MAP_EDIT_EVENT } from './config';
import { eventBus } from '@/utils/eventBus';

const props = defineProps({
  mapId: {
    type: String,
    required: true,
  },
  // 地图初始化参数
  mapInitOptions: {
    type: Object,
    default: () => ({}),
  },
  // 是否需要绘制工具minemap-edit，文档地址：https://minedata.cn/minemapapi/minemap-plugins/edit/edit-api.html
  withDarw: {
    type: Boolean,
    default: false,
  }
})

onMounted(async () => {
  await loadMapSource();
  map.value = getMapInstance({ domRef: mapRef.value, ...props.mapInitOptions });
  map.value.mapId = props.mapId;
  map.value.once('load', async () => {
    if (props.withDarw) {
      await loadMapEditSource();
      initEditControl();
    } else {
      handleMapReadyResolve();
    }
  });
})

onUnmounted(() => {
  removeDrawControl();
})

const mapRef = useTemplateRef('mapRef');
const map = ref(null);
const mapEditor = ref(null);
let mapReadyResolve = null;
let mapReadyPrimise = new Promise(resolve => mapReadyResolve = resolve);

const onMapReady = () => {
  return mapReadyPrimise; // 不能将new Promise直接写到函数内部，否则会重复创建promise
};

const handleMapReadyResolve = () => {
  if (typeof mapReadyResolve != 'function') return;
  if (props.withDarw) mapReadyResolve({ map: map.value, mapEditor: mapEditor.value });
  else mapReadyResolve({ map: map.value });
};

const initEditControl = () => {
  if (!minemap || !minemap.edit || !minemap.edit.init) {
    console.error('initEditControl Error: minemap or minemap.edit.init not found');
    return;
  }
  mapEditor.value = new minemap.edit.init(map.value, {
    boxSelect: true,    /* 是否支持拉框选择 */
    touchEnabled: true,    /* 是否支持手指触屏 */
    displayControlsDefault: false,   /* 是否启用编辑控件 */
    showButtons: false  /* 是否启用默认控件按钮 */
  })
  addEditListeners();
  handleMapReadyResolve();
  console.log('----- map initEditControl success -----', mapEditor.value);
};

const addEditListeners = () => {
  // 操作一：双击结束绘制，进入选中态(不触发selected)：触发create，数据编辑中创建数据，并选中
  // 操作二：点击图形外(选中态时)，取消选中态，触发unselected，数据编辑中取消选中
  // 操作三：单击图形，进入选中态，触发selected，数据编辑中选中
  // 操作四：双击图形，进入编辑态，触发draw.modechange(e.mode=direct_select)，(同时双击的第一次点击也会触发selected)，数据编辑中选中
  // 操作五：点击图形外(编辑态时)，取消编辑态，触发draw.modechange(在出现e.mode=direct_select后再出现e.mode=simple_select)，数据编辑中取消选中
  // 操作六：编辑态时，两顶点间出现临时顶点，draw.update触发时机：点击临时顶点触发，点击后并拖拽触发，拖动顶点与临时顶点间的线段松手后触发，数据编辑中修改图形数据
  if (!mapEditor.value) return;
  map.value.on('draw.create', onMapEditCreate); // 绘制图形双击结束时触发，并进入选中态，离焦后触发unselected
  map.value.on('edit.selected', onMapEditSelected); // 单击(包括双击的第一次点击)图形进入选中态时触发，用于与数据编辑中的数据联动选择
  map.value.on('edit.unselected', onMapEditSelectedCancel); // 单击(不包括双击)进入从选中态退出选中态时触发，用于与数据编辑中的数据联动选择
  map.value.on("draw.modechange", onMapEditChange); // 双击出现direct_select进入编辑态，点击其他地方出现simple_select代表退出编辑态
  map.value.on('draw.update', onMapEditUpdate); // 双击进入编辑态，变更图形时触发
  // map.value.on('edit.record.create', () => { console.log('draw.create', e) }) // 图形删除、新增、修改、属性更新、图形合并拆分等会产生新增的操作记录
  // map.value.on('draw.selectionchange', e => { console.log('draw.selectionchange', e) }) // 单击图形、双击图形(每次点击触发一次，共两次)、编辑态点击顶点
  // map.value.on('draw.actionable', e => { console.log('draw.actionable', e) })
  onMapEditDelete(); // 临时删除事件

  // 
  mapEditor.value.eventListeners = [];

  mapEditor.value.addEventListener = (eventName, callback) => {
    if (!Object.values(MAP_EDIT_EVENT).includes(eventName)) {
      console.error(`Error in addEventListener: ${eventName} is not a valid event name.`);
      return;
    }
    if (typeof callback !== 'function') {
      console.error(`Error in addEventListener: Callback must be a function.`);
      return;
    }
    mapEditor.value.eventListeners.push({ eventName, callback });
  }

  mapEditor.value.removeEventListener = (eventName, callback) => {
    if (!Object.values(MAP_EDIT_EVENT).includes(eventName)) {
      console.error(`Error in removeEventListener: ${eventName} is not a valid event name.`);
      return;
    }
    if (typeof callback !== 'function') {
      console.error(`Error in addEventListener: Callback must be a function.`);
      return;
    }
    mapEditor.value.eventListeners = mapEditor.value.eventListeners.filter(item => item.eventName !== eventName || item.callback !== callback);
  }

  mapEditor.value.dispatchEvent = (eventName, data) => {
    if (!Array.isArray(mapEditor.value.eventListeners)) return;
    mapEditor.value.eventListeners.forEach(item => {
      if (item.eventName === eventName && typeof item.callback === 'function') {
        try {
          item.callback(data);
        } catch (error) {
          console.error(`Error in dispatchEvent(event listener ${eventName}):`, error);
        }
      }
    });
  }
}

const clearEditListeners = () => {
  if (!mapEditor.value) return;
  map.value.off('draw.create', onMapEditCreate);
  map.value.off('edit.selected', onMapEditSelected);
  map.value.off('edit.unselected', onMapEditSelectedCancel);
  map.value.off('draw.modechange', onMapEditChange);
  map.value.off('draw.update', onMapEditUpdate);
}

const getMapEditEventParams = data => ({ map: map.value, mapEditor: mapEditor.value, data })

const onMapEditCreate = e => {
  const params = getMapEditEventParams(e);
  eventBus.emit(MAP_EDIT_EVENT.CREATED, params)
  mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.CREATED, params);
}

let currSelectedData = null;
const onMapEditSelected = e => {
  currSelectedData = e;
  const params = getMapEditEventParams(e);
  eventBus.emit(MAP_EDIT_EVENT.SELECTED, params)
  mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.SELECTED, params);
}

const onMapEditSelectedCancel = e => {
  currSelectedData = null;
  const params = getMapEditEventParams(e);
  eventBus.emit(MAP_EDIT_EVENT.SELECTED_CANCEL, params)
  mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.SELECTED_CANCEL, params);
}

let preMode = null;
const onMapEditChange = e => {
  if (!preMode && e.mode == 'simple_select') return; // 排除双击创建时触发的情况
  if (!preMode && e.mode == 'direct_select') {
    const params = getMapEditEventParams(currSelectedData); // 用的是edit.selected事件的数据，因为draw.modechange没有关于featureId的数据
    eventBus.emit(MAP_EDIT_EVENT.EDIT, params);
    mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.EDIT, params);
    preMode = e.mode;
    return;
  }
  if (preMode == 'direct_select' && e.mode == 'simple_select') {
    const params = getMapEditEventParams(currSelectedData);
    eventBus.emit(MAP_EDIT_EVENT.EDIT_CANCEL, params);
    mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.EDIT_CANCEL, params);
    preMode = null;
    currSelectedData = null;
  }
}

const onMapEditUpdate = e => {
  const params = getMapEditEventParams(e);
  eventBus.emit(MAP_EDIT_EVENT.UPDATE, params)
  mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.UPDATE, params);
}

// minemap本身支持delete删除，但是删除事件没有触发。这里临时手动处理下。
const onMapEditDelete = () => {
  mapRef.value.addEventListener('keydown', e => {
    if (e.key != 'Delete') return;
    e.preventDefault();
    e.stopPropagation();
    const selectFeatureCollection = mapEditor.value.draw.getSelected();
    const selectFeatureIds = selectFeatureCollection.features.map(item => item.id);
    mapEditor.value.draw.delete(selectFeatureIds);
    const params = getMapEditEventParams({ featureIds: selectFeatureIds });
    eventBus.emit(MAP_EDIT_EVENT.DELETE, params)
    mapEditor.value.dispatchEvent(MAP_EDIT_EVENT.DELETE, params);
  })
};

const removeDrawControl = () => {
  clearEditListeners();
  if (!mapEditor.value) return;
  mapEditor.value.dispose();
  console.log('----- map removeDrawControl success -----');
};

defineExpose({
  map,
  mapEditor,
  onMapReady, // 外部通过异步方式等待地图初始化完成
})
</script>

<style lang="scss" scoped>
.map {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
</style>